﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Basmus.ReadWrite;
using Basmus.Values;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Basmus.Tests.WebLink
{
    [TestClass]
    public class CompositeValueProviderTests
    {
        [TestMethod]
        public void GetValues_OneValueByNameWith1Provider_ReturnThisValue()
        {
            //Arrange
            var stubProvider = new Mock<IValuesProvider<string>>();
            stubProvider.Setup(p => p.GetValues("Name2")).Returns(new[] { "Foo" });
            var provider = new CompositeValuesProvider<string>(new[] { stubProvider.Object }, false);

            //Act
            var values = provider.GetValues("Name2");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith1Provider_ReturnTheseValues()
        {
            //Arrange
            var stubProvider = new Mock<IValuesProvider<string>>();
            stubProvider.Setup(p => p.GetValues("Name1")).Returns(new[] { "abcde", "123" });
            var provider = new CompositeValuesProvider<string>(new[] { stubProvider.Object }, false);

            //Act
            var values = provider.GetValues("Name1");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "abcde", "123" }, values);
        }

        [TestMethod]
        public void GetValues_OneValueByNameWith1MergedProvider_ReturnThisValue()
        {
            //Arrange
            var stubProvider = new Mock<IValuesProvider<string>>();
            stubProvider.Setup(p => p.GetValues("Name2")).Returns(new[] { "Foo" });
            var provider = new CompositeValuesProvider<string>(new[] { stubProvider.Object }, true);

            //Act
            var values = provider.GetValues("Name2");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith1MergedProvider_ReturnTheseValues()
        {
            //Arrange
            var stubProvider = new Mock<IValuesProvider<string>>();
            stubProvider.Setup(p => p.GetValues("Name1")).Returns(new[] { "abcde", "123" });
            var provider = new CompositeValuesProvider<string>(new[] { stubProvider.Object }, true);

            //Act
            var values = provider.GetValues("Name1");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "abcde", "123" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith3Provider_ReturnValuesOfFirstProvider()
        {
            //Arrange
            var stubProvider1 = new Mock<IValuesProvider<string>>();
            var stubProvider2 = new Mock<IValuesProvider<string>>();
            var stubProvider3 = new Mock<IValuesProvider<string>>();
            stubProvider1.Setup(p => p.GetValues("Name3")).Returns(new[] { "Foo1" });
            stubProvider2.Setup(p => p.GetValues("Name3")).Returns(new[] { "Bar" });
            stubProvider3.Setup(p => p.GetValues("Name3")).Returns(new[] { "256", "8", "FE" });
            var stubProviders = new[] {stubProvider1.Object, stubProvider2.Object, stubProvider3.Object};
            var provider = new CompositeValuesProvider<string>(stubProviders, false);

            //Act
            var values = provider.GetValues("Name3");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo1" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith3ProviderSecondEmpty_ReturnValuesOfFirstProvider()
        {
            //Arrange
            var stubProvider1 = new Mock<IValuesProvider<string>>();
            var stubProvider2 = new Mock<IValuesProvider<string>>();
            var stubProvider3 = new Mock<IValuesProvider<string>>();
            stubProvider1.Setup(p => p.GetValues("Name3")).Returns(new[] { "Foo1" });
            stubProvider2.Setup(p => p.GetValues("Name3")).Returns<IEnumerable<string>>(null);
            stubProvider3.Setup(p => p.GetValues("Name3")).Returns(new[] { "256", "8", "FE" });
            var stubProviders = new[] { stubProvider1.Object, stubProvider2.Object, stubProvider3.Object };
            var provider = new CompositeValuesProvider<string>(stubProviders, false);

            //Act
            var values = provider.GetValues("Name3");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo1" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith3ProviderFirstEmpty_ReturnValuesOfSecondProvider()
        {
            //Arrange
            var stubProvider1 = new Mock<IValuesProvider<string>>();
            var stubProvider2 = new Mock<IValuesProvider<string>>();
            var stubProvider3 = new Mock<IValuesProvider<string>>();
            stubProvider1.Setup(p => p.GetValues("Name3")).Returns<IEnumerable<string>>(null);
            stubProvider2.Setup(p => p.GetValues("Name3")).Returns(new[] { "Bar" });
            stubProvider3.Setup(p => p.GetValues("Name3")).Returns(new[] { "256", "8", "FE" });
            var stubProviders = new[] { stubProvider1.Object, stubProvider2.Object, stubProvider3.Object };
            var provider = new CompositeValuesProvider<string>(stubProviders, false);

            //Act
            var values = provider.GetValues("Name3");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Bar" }, values);
        }

        [TestMethod]
        public void GetValues_ValuesByNameWith3MergedProvider_ReturnValuesInProvidersOrder()
        {
            //Arrange
            var stubProvider1 = new Mock<IValuesProvider<string>>();
            var stubProvider2 = new Mock<IValuesProvider<string>>();
            var stubProvider3 = new Mock<IValuesProvider<string>>();
            stubProvider1.Setup(p => p.GetValues("Name3")).Returns(new[] { "Foo1" });
            stubProvider2.Setup(p => p.GetValues("Name3")).Returns(new[] { "Bar" });
            stubProvider3.Setup(p => p.GetValues("Name3")).Returns(new[] { "256", "8", "FE" });
            var stubProviders = new[] { stubProvider1.Object, stubProvider2.Object, stubProvider3.Object };
            var provider = new CompositeValuesProvider<string>(stubProviders, true);

            //Act
            var values = provider.GetValues("Name3");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo1", "Bar", "256", "8", "FE" }, values);
        }

        

        [TestMethod]
        public void GetValues_ValuesByNameWith3MergedProvider1Empty_ReturnValuesInProvidersOrder()
        {
            //Arrange
            var stubProvider1 = new Mock<IValuesProvider<string>>();
            var stubProvider2 = new Mock<IValuesProvider<string>>();
            var stubProvider3 = new Mock<IValuesProvider<string>>();
            stubProvider1.Setup(p => p.GetValues("Name3")).Returns(new[] { "Foo1" });
            stubProvider2.Setup(p => p.GetValues("Name3")).Returns<IEnumerable<string>>(null);
            stubProvider3.Setup(p => p.GetValues("Name3")).Returns(new[] { "256", "8", "FE" });
            var stubProviders = new[] { stubProvider1.Object, stubProvider2.Object, stubProvider3.Object };
            var provider = new CompositeValuesProvider<string>(stubProviders, true);

            //Act
            var values = provider.GetValues("Name3");

            //Assert
            CollectionAssertHelper.AreEqual(new[] { "Foo1", "256", "8", "FE" }, values);
        }

    }
}
